flag_set.hpp
namespace type_safe
{
template <typename Enum>
struct flag_set_traits;
struct noflag_t;
constexpr noflag_t noflag;
template <typename Enum>
using flag_combo = 'hidden';
template <typename Enum>
using flag_mask = 'hidden';
template <typename Enum>
constexpr flag_combo<Enum> combo(const flag_mask<Enum>& mask) noexcept;
template <typename Enum>
constexpr flag_mask<Enum> mask(const Enum& flag) noexcept;
template <typename Enum>
constexpr flag_mask<Enum> mask(const flag_combo<Enum>& combo) noexcept;
template <typename Enum>
class flag_set;
template <typename Enum>
constexpr flag_combo<Enum> combo(const flag_set<Enum>& set) noexcept;
template <typename Enum>
constexpr flag_mask<Enum> mask(const flag_set<Enum>& set) noexcept;
//=== flag_set equality comparison ===//
template <typename Enum>
constexpr bool operator==(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;
template <typename Enum>
constexpr bool operator==(const flag_set<Enum>& a, noflag_t b) noexcept;
template <typename Enum>
constexpr bool operator==(noflag_t a, const flag_set<Enum>& b) noexcept;
template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator==(const flag_set<Enum>& a, const FlagCombo& b) noexcept;
template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator==(const FlagCombo& a, const flag_set<Enum>& b) noexcept;
template <typename Enum>
constexpr bool operator!=(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;
template <typename Enum>
constexpr bool operator!=(const flag_set<Enum>& a, noflag_t b) noexcept;
template <typename Enum>
constexpr bool operator!=(noflag_t a, const flag_set<Enum>& b) noexcept;
template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator!=(const flag_set<Enum>& a, const FlagCombo& b) noexcept;
template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator!=(const FlagCombo& a, const flag_set<Enum>& b) noexcept;
//=== Bitwise operations for flag_set ===//
template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator|(const flag_set<Enum>& a, const FlagCombo& b);
template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator|(const FlagCombo& a, const flag_set<Enum>& b);
template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator^(const flag_set<Enum>& a, const FlagCombo& b);
template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator^(const FlagCombo& a, const flag_set<Enum>& b);
template <typename Enum>
constexpr flag_set<Enum> operator&(const flag_set<Enum>& a, const flag_mask<Enum>& b);
template <typename Enum>
constexpr flag_set<Enum> operator&(const flag_mask<Enum>& a, const flag_set<Enum>& b);
//=== Bitwise and for flag_set ===//
template <typename Enum, typename FlagCombo>
constexpr bool operator&(const flag_set<Enum>& a, const FlagCombo& b);
template <typename Enum, typename FlagCombo>
constexpr bool operator&(const FlagCombo& a, const flag_set<Enum>& b);
}
template <typename Enum>
constexpr type_safe::flag_mask<Enum> operator~(const Enum& e) noexcept;
template <typename Enum>
constexpr type_safe::flag_combo<Enum> operator|(const Enum& a, const Enum& b) noexcept;
type_safe::flag_set_traits
template <typename Enum>
struct flag_set_traits
: 'hidden'
{
static constexpr std::size_t size() noexcept;
};
Traits for the enum used in a ts::flag_set.
For each enum that should be used with ts::flag_set it must provide the following interface:
static constexpr std::size_t size()
that returns the number of enumerators.The default specialization automatically works for enums that have an enumerator _flag_set_size
, whose value is the number of enumerators. But you can also specialize the traits for your own enums. Enums which work with ts::flag_set are called flags.
Requires: For all specializations the enum must be contiguous starting at 0
, simply don't set an explicit value to the enumerators.
type_safe::noflag_t
struct noflag_t
{
constexpr noflag_t();
};
Tag type to mark a ts::flag_set without any flags set.
type_safe::noflag
constexpr noflag_t noflag;
Tag object of type ts::noflag_t.
type_safe::flag_combo
template <typename Enum>
using flag_combo = 'hidden';
Represents a combination of multiple flags.
This type is created when you write a | b
, where a
and b
are enumerators of a flag.
Objects of this type and the flags themselves are flag combinations. You can compare two flag combinations, combine two with |
and use them in ts::flag_set to set or toggle a combination of flags. Creating the complement with ~
will create a ts::flag_mask.
Requires: Enum
must be a flag, i.e. valid with the ts::flag_set_traits.
type_safe::flag_mask
template <typename Enum>
using flag_mask = 'hidden';
Represents a mask of flags.
This type is created when you write ~a
, where a
is the enumerator of a flag.
Objects of this type are flag masks. You can compare two flag masks, combine them with &
and use them in ts::flag_set to clear a combination of flags. Creating the complement with ~
will create a ts::flag_combo.
Requires: Enum
must be a flag, i.e. valid with the ts::flag_set_traits.
type_safe::combo
template <typename Enum>
constexpr flag_combo<Enum> combo(const flag_mask<Enum>& mask) noexcept;
Converts a flag mask to a flag combination.
Returns: The flag combination with the same value as the mask.
Notes: As you cannot use a mask to set flags in a ts::flag_set, you cannot write ~a
to set all flags except a
directly, you have to be explicit.
type_safe::mask
(1) template <typename Enum>
constexpr flag_mask<Enum> mask(const Enum& flag) noexcept;
(2) template <typename Enum>
constexpr flag_mask<Enum> mask(const flag_combo<Enum>& combo) noexcept;
Converts a flag combination to a flag mask.
Returns: The flag mask with the same value as the flag combination.
Notes: (1) does not participate in overload resolution, unless the argument is a flagg.
Notes: As you cannot use a combination to clear flags in a ts::flag_set, you cannot write a
to clear all flags except a
directly, you have to be explicit.
type_safe::flag_set
template <typename Enum>
class flag_set
{
public:
constexpr flag_set() noexcept;
constexpr flag_set(noflag_t) noexcept;
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr flag_set(const FlagCombo& combo) noexcept;
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator=(const FlagCombo& combo) noexcept;
flag_set& operator=(noflag_t) noexcept;
void set(const Enum& flag) noexcept;
template <typename T>
void set(const Enum& flag, T value) noexcept;
void set(const Enum& f, flag value) noexcept;
void reset(const Enum& flag) noexcept;
void toggle(const Enum& flag) noexcept;
void set_all() noexcept;
template <typename T>
void set_all(T value) noexcept;
void set_all(flag value) noexcept;
void reset_all() noexcept;
void toggle_all() noexcept;
constexpr bool is_set(const Enum& flag) const noexcept;
constexpr flag as_flag(const Enum& flag) const noexcept;
constexpr bool any() const noexcept;
constexpr bool all() const noexcept;
constexpr bool none() const noexcept;
template <typename T>
constexpr T to_int() const noexcept;
constexpr flag_set operator~() const noexcept;
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator|=(const FlagCombo& other) noexcept;
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator^=(const FlagCombo& other) noexcept;
flag_set& operator&=(const flag_mask<Enum>& other) noexcept;
};
A set of flags where each one can either be 0
or 1
.
Each enumeration member represents the index of one bit.
Unlike ts::flag_combo or ts::flag_mask this does not have this semantic distinction. It is just a generic container of flags, which can be set, cleared or toggled. It can be interpreted as either a flag combination or flag mask, however.
Requires: Enum
must be a flag, i.e. valid with the ts::flag_set_traits.
type_safe::flag_set::flag_set
(1) constexpr flag_set() noexcept;
(2) constexpr flag_set(noflag_t) noexcept;
Effects: Creates a set where all flags are set to 0
.
type_safe::flag_set::flag_set
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr flag_set(const FlagCombo& combo) noexcept;
Effects: Creates a set where all bits are set to 0
except the given ones.
Notes: This constructor only participates in overload resolution if the argument is a flag combination.
type_safe::flag_set::operator=
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator=(const FlagCombo& combo) noexcept;
Effects: Same as *this = flag_set(combo)
.
type_safe::flag_set::operator=
flag_set& operator=(noflag_t) noexcept;
Effects: Same as reset_all.
type_safe::flag_set::set
(1) void set(const Enum& flag) noexcept;
(2) template <typename T>
void set(const Enum& flag, T value) noexcept;
(3) void set(const Enum& f, flag value) noexcept;
Effects: Sets the specified flag to 1
(1)/value
(2/3).
Notes: (2) does not participate in overload resolution unless T
is a boolean-like type.
type_safe::flag_set::reset
void reset(const Enum& flag) noexcept;
Effects: Sets the specified flag to 0
.
type_safe::flag_set::toggle
void toggle(const Enum& flag) noexcept;
Effects: Toggles the specified flag.
type_safe::flag_set::set_all
(1) void set_all() noexcept;
(2) template <typename T>
void set_all(T value) noexcept;
(3) void set_all(flag value) noexcept;
(4) void reset_all() noexcept;
(5) void toggle_all() noexcept;
Effects: Sets/resets/toggles all flags.
type_safe::flag_set::is_set
constexpr bool is_set(const Enum& flag) const noexcept;
Returns: Whether or not the specified flag is set.
type_safe::flag_set::as_flag
constexpr flag as_flag(const Enum& flag) const noexcept;
Returns: Same as flag(is_set(flag))
.
type_safe::flag_set::any
constexpr bool any() const noexcept;
Returns: Whether any flag is set.
type_safe::flag_set::all
constexpr bool all() const noexcept;
Returns: Whether all flags are set.
type_safe::flag_set::none
constexpr bool none() const noexcept;
Returns: Whether no flag is set.
type_safe::flag_set::to_int
template <typename T>
constexpr T to_int() const noexcept;
Returns: An integer where each bit has the value of the corresponding flag.
Requires: T
must be an unsigned integer type with enough bits.
type_safe::flag_set::operator~
constexpr flag_set operator~() const noexcept;
Returns: A set with all the flags flipped.
type_safe::flag_set::operator|=
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator|=(const FlagCombo& other) noexcept;
Effects: Sets all flags that are set in the given flag combination.
Returns: *this
Notes: This operator does not participate in overload resolution, unless the argument is a flag combination. If you truly want to write set |= ~a
, i.e. set all flags except a
, use set |= combo(~a)
.
type_safe::flag_set::operator^=
template <typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
flag_set& operator^=(const FlagCombo& other) noexcept;
Effects: Toggles all flags that are set in the given flag combination.
Returns: *this
Notes: This operator does not participate in overload resolution, unless the argument is a flag combination. If you truly want to write set ^= ~a
, i.e. toggle all flags except a
, use set ^= combo(~a)
.
type_safe::flag_set::operator&=
flag_set& operator&=(const flag_mask<Enum>& other) noexcept;
Effects: Clears all flags that aren't set in the given flag mask.
Returns: *this
Notes: This operator does not participate in overload resolution, unless the argument is a flag mask. If you truly want to write set &= a
, i.e. clear all flags except a
, use set &= mask(a)
.
type_safe::combo
template <typename Enum>
constexpr flag_combo<Enum> combo(const flag_set<Enum>& set) noexcept;
Converts a ts::flag_set to a flag combination.
Returns: The flag combination with the same value as the set.
type_safe::mask
template <typename Enum>
constexpr flag_mask<Enum> mask(const flag_set<Enum>& set) noexcept;
Converts a ts::flag_set to a flag mask.
Returns: The flag mask with the same value as the set.
(1) template <typename Enum>
constexpr bool operator==(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;
(2) template <typename Enum>
constexpr bool operator==(const flag_set<Enum>& a, noflag_t b) noexcept;
(3) template <typename Enum>
constexpr bool operator==(noflag_t a, const flag_set<Enum>& b) noexcept;
(4) template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator==(const flag_set<Enum>& a, const FlagCombo& b) noexcept;
(5) template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator==(const FlagCombo& a, const flag_set<Enum>& b) noexcept;
(6) template <typename Enum>
constexpr bool operator!=(const flag_set<Enum>& a, const flag_set<Enum>& b) noexcept;
(7) template <typename Enum>
constexpr bool operator!=(const flag_set<Enum>& a, noflag_t b) noexcept;
(8) template <typename Enum>
constexpr bool operator!=(noflag_t a, const flag_set<Enum>& b) noexcept;
(9) template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator!=(const flag_set<Enum>& a, const FlagCombo& b) noexcept;
(10) template <typename Enum, typename FlagCombo, typename = detail::enable_flag_combo<FlagCombo, Enum>>
constexpr bool operator!=(const FlagCombo& a, const flag_set<Enum>& b) noexcept;
flag_set
equality comparison.
Returns: Whether both flag sets have the same combination of flags set/not set.
(1) template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator|(const flag_set<Enum>& a, const FlagCombo& b);
(2) template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator|(const FlagCombo& a, const flag_set<Enum>& b);
(3) template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator^(const flag_set<Enum>& a, const FlagCombo& b);
(4) template <typename Enum, typename FlagCombo>
constexpr flag_set<Enum> operator^(const FlagCombo& a, const flag_set<Enum>& b);
(5) template <typename Enum>
constexpr flag_set<Enum> operator&(const flag_set<Enum>& a, const flag_mask<Enum>& b);
(6) template <typename Enum>
constexpr flag_set<Enum> operator&(const flag_mask<Enum>& a, const flag_set<Enum>& b);
Returns: The same as a Op= b
.
(1) template <typename Enum, typename FlagCombo>
constexpr bool operator&(const flag_set<Enum>& a, const FlagCombo& b);
(2) template <typename Enum, typename FlagCombo>
constexpr bool operator&(const FlagCombo& a, const flag_set<Enum>& b);
Checks whether a combination of flags is set in a
.
Returns: true
if all the flags set in b
are also set in a
, false
otherwise.
Notes: These functions do not participate in overload resolution, unless FlagCombo
is a flag operation.
operator~
template <typename Enum>
constexpr type_safe::flag_mask<Enum> operator~(const Enum& e) noexcept;
Creates a ts::flag_mask for the single enum value.
Returns: A ts::flag_mask where all bits are set, unless the given one.
Notes: This function does not participate in overload resolution, unless Enum
is an enum
where the ts::flag_set_traits are specialized.
operator|
template <typename Enum>
constexpr type_safe::flag_combo<Enum> operator|(const Enum& a, const Enum& b) noexcept;
Creates a ts::flag_combo from two enums.
Returns: A ts::flag_combo where the two given bits are set.
Notes: These functions do not participate in overload resolution, unless Enum
is an enum
where the ts::flag_set_traits are specialized.